package com.gopi.utilities.gui;

import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import com.gopi.utilities.action.AbstractController;
import com.gopi.utilities.action.MenuItemDescriptor;
import com.gopi.utilities.common.Disposable;

/**
 * This Tree is build on the top of JTree, with a default scroll pane.
 * This tree also adds the functionality of adding pop up menus to the
 * tree easily. All node added to the tree must extend
 * NewAbstractTreeNode 
 * 
 * @see NewAbstractTreeNode
 * 
 * @author gopi
 *
 */

public class ScrollTree implements Disposable,MouseListener
{
	private JTree tree;
	private JScrollPane pane;
	private Map<Integer,JPopupMenu> mPopupMap;
	private boolean isPopupMenusUsed;
	
	private CustomTreeCellRenderer renderer;
	
	public ScrollTree()
	{
		;
	}
	
	public ScrollTree(TreeModel model)
	{
		this(model,null,true);
	}
	
	public ScrollTree(TreeNode node)
	{
		this(null,node,true);
	}

	public ScrollTree(TreeNode node,boolean allowChildren)
	{
		this(null,node,true);
	}
	
	public ScrollTree(TreeModel model,TreeNode node,boolean allowChildren)
	{
		if(model==null)
			tree = new JTree(node,allowChildren);
		else
			tree = new JTree(model);
			
		tree.setCellRenderer(renderer = new CustomTreeCellRenderer());
		pane = new JScrollPane(tree);
		pane.setViewportView(tree);
		mPopupMap = new HashMap<Integer,JPopupMenu>();
	}

	public void expand(TreeNode node)
	{
		
	}

	public void setTree(JTree tree)
	{
		this.tree = tree;
	}
	
	public JTree getTree()
	{
		return this.tree;
	}
	
	public Object getRootNode()
	{
		return tree.getModel().getRoot();
	}
	/**
	 * This method should be called to add the tree component to any component.
	 * This method actually returns ScrollPane inside which tree lives.
	 * 
	 * @return JComponent
	 */
	public JComponent getRenderComponent()
	{
		return pane;
	}
	
	public void addNode(MutableTreeNode parentNode,MutableTreeNode newNode)
	{
		addNode(parentNode, newNode,  parentNode.getChildCount());
	}
	
	public void addNode(MutableTreeNode parentNode,MutableTreeNode newNode,int index)
	{
		((DefaultTreeModel) tree.getModel()).insertNodeInto(newNode,parentNode,index);
	}

	public void removeChild(MutableTreeNode parentNode)
	{
		int count = parentNode.getChildCount();
		for(int i = 0;i<count;i++)
			((DefaultTreeModel) tree.getModel()).removeNodeFromParent(
					(MutableTreeNode)parentNode.getChildAt(0)) ;
	}
	
	public void updateNode(TreeNode node)
	{
		((DefaultTreeModel) tree.getModel()).nodeChanged(node);
	}

	public NewAbstractTreeNode getSelectedTreeNode()
	{
		TreePath path = getTree().getSelectionPath();
		//System.out.println("Selected " + path.getLastPathComponent().toString());
		return path!=null ? (NewAbstractTreeNode) path.getLastPathComponent() : null;
	}
	
	public static NewAbstractTreeNode getSelectedTreeNode(JTree tree)
	{
		TreePath path = tree.getSelectionPath();
		//System.out.println("Selected " + path.getLastPathComponent().toString());
		return path!=null ? (NewAbstractTreeNode) path.getLastPathComponent() : null;
	}
	
	/**
	 * You should call this method, if the tree is going to use pop up menus.
	 * If you are not going to use pop up menus, <b>Don't call this method</b>.
	 *
	 */
	public void initPopup()
	{
		isPopupMenusUsed = true;
		getTree().addMouseListener(this);
	}
	
	public void addPopupMenu(Integer type,List<MenuItemDescriptor> menuItemsDesc,AbstractController controller)
	{
		JPopupMenu menu;
		JMenuItem menuItem;
		menu = mPopupMap.get(type);
		if(menu==null)
		{
			menu = new JPopupMenu();
			mPopupMap.put(type,menu);
		}
		for(MenuItemDescriptor menuItemDesc : menuItemsDesc)
		{
			menuItem = menuItemDesc.buildMenuItemUsingDescriptor(controller);
			controller.addActionCommand(menuItem.getActionCommand(),
					menuItem);
			if(menuItemDesc.getChildCount()!=0)
			{
				menu.add(menuItemDesc.buildMenuItemUsingDescriptor(controller));
			}
			else
			{
				menu.add(menuItem);
			}
		}
	}
	
	public void dispose() 
	{
		tree = null;
		pane = null;
		mPopupMap.clear();
		mPopupMap = null;
		if(isPopupMenusUsed)
		{
			
		}
	}

	public void mouseClicked(MouseEvent e) {}

	public void mouseEntered(MouseEvent e) {} 

	public void mouseExited(MouseEvent e) {}

	public void mousePressed(MouseEvent e) {} 

	public void mouseReleased(MouseEvent e) 
	{
		System.out.println("Released");
		if(e.getButton()==MouseEvent.BUTTON3)
		{
			TreePath path = getTree().getPathForLocation(e.getX(), e.getY());
			if(path!=null)
			{
				Integer type = ((NewAbstractTreeNode)path.getLastPathComponent()).getNodeTypeForMenu();
				if(type>NewAbstractTreeNode.NO_MENU)
				{
					getTree().setSelectionPath(getTree().getPathForLocation(e.getX(), e.getY()));
					showMenu(type,e);
				}
			}
		}
	}
	
	private void showMenu(Integer nodeType,MouseEvent e)
	{
		JPopupMenu menu = mPopupMap.get(nodeType);
		if(menu!=null)
		{
			menu.show( (Component) e.getSource(),e.getX(),e.getY() );
		}
	}
}
